#include <config.h>
#ifdef LANG_X86

;
; Process.s -- Provides assembler functions for switching processes.
;

;
; Switches the current process.
;
[GLOBAL switchProcess]
switchProcess:
  cli                 ; Critical point - uninterruptible
  mov ebp, esp
  mov ebx, [ebp+16]   ; Put the base pointer in ebx
  mov eax, [ebp+12]   ; Put the stack pointer in eax
  mov ecx, [ebp+8]    ; Put the instruction pointer in ecx
  mov edx, [ebp+4]    ; Put the page directory in edx.
  
  mov cr3, edx        ; Change the page directory
  
  mov ebp, ebx        ; Change base pointer
  mov esp, eax        ; Change stacks.

  mov eax, 0x20       ; Put our magic return value in eax.

  sti                 ; Restart interrupts after the next instruction
  jmp ecx             ; Jump to new location

;
; Switches the processor to user-mode (ring 3)
;
[GLOBAL switchToUserMode]
switchToUserMode:
  mov   ax, 0x23        ; Load the new data segment descriptor with an RPL of 3.
  mov   ds, ax          ; Propagate the change to all segment registers.
  mov   es, ax
  mov   fs, ax
  mov   gs, ax
  
  sti                   ; Must STI BEFORE pushfd!
  mov   eax, esp        ; Save the stack pointer before pushing anything
  push  0x23            ; Push the new stack segment with an RPL of 3.
  push  eax             ; Push what the was ESP before pushing anything.
  
  pushfd                ; Push EFLAGS
  push 0x1B             ; Push the new code segment with an RPL of 3.
  push .usermode_return ; Push the EIP to IRET to.
  
  iret
  
.usermode_return:
  ret

; [GLOBAL fastSyscall]
; fastSyscall:
;   mov ecx, ebp          ; Current stack frame start.
;   mov edx, ebx          ; __cdecl states we must save ebx.
;   mov ebx, ebp          ; ebx = stack frame size
;   sub ebx, esp          ;     = (ebp-esp)
; 
;   mov eax, .syscall_end ; eax = EIP to return to.
; 
;   sysenter              ; Make syscall.
; 
; .syscall_end:
;   sti
;   ret
; 
; [GLOBAL fastSysexit]
; fastSysexit:
;   cli
;   mov eax, [esp+8]      ; Get the return value.
;   mov edx, [esp+4]      ; Dereference parameter - esp = *(esp0) - go back to the
;   mov esp, [edx-4]      ; beginning of our stack frame and dereference what we 
;                         ; find, which will be the esp pushed in the handler.
;   mov ebx, [edx-8]      ; Get the old value of EBX back (__cdecl)
;   mov esi, [edx-12]     ; Restore ESI's state.
;   mov edi, [edx-16]     ; Restore EDI's state.
;   
;   pop ebp               ; Return ebp to what it was before we were called.
;   pop edx               ; EDX = EIP return pointer
;   mov ecx, esp          ; Return ESP
;   sti
;   sysexit
; 
; [GLOBAL fastSysexitExecve]
; fastSysexitExecve:
;   mov eax, [esp+4]      ; The first parameter is the value of eax (argv).
;   mov ebx, [esp+8]      ; The second parameter is the value of ebx (env).
;   mov ecx, [esp+12]     ; New stack pointer (in ecx for sysexit)
;   mov edx, [esp+16]     ; New EIP (in EDX for sysexit)
;   
;   sysexit
; 
; [GLOBAL fastSyscallHandler]
; fastSyscallHandler:
;   sti                   ; SYSENTER kills interrupts. Reenable them.
;   push ecx              ; Push the old stack pointer on the new stack.
;   push edx              ; EDX contains what was EBX. we must save this to comply
;                         ; with __cdecl.
;   push esi              ; Have to maintain ESI's state also.
;   push edi              ; And EDI.
;   
;   sub esp, 0x4
; 
;   mov esi, 0x80         ; TODO: make this 0x20 dynamic, so as to copy all params.
;   add ecx, 0x80
; .loop:                  ; copy 0x20 before the thingy as well
;   mov edx, [ecx]
;   mov [esp], edx
;   sub esp, 0x4
;   sub ecx, 0x4
;   sub esi, 0x4
;   jnz .loop
;   
;   mov ebp, esp          ; Set up our new base pointer
;   mov edx, ebx          ; store the frame size.
;   mov ebx, ebp          ; EBX = stack base ptr -stack frame size.
;   sub ebx, edx          ; do the subtraction.
; 
; .loop2:
;   mov edx, [ecx]        ; Copy [ecx] to [esp] ( copying stack frame to kernelspace )
;   mov [esp], edx
;   sub esp, 0x4          ; Next word, working down the stack.
;   sub ecx, 0x4          ; Next work, working down the stack.
;   cmp esp, ebx          ; do while esp < frame size + base ptr
;   jnz .loop2
;   
;   mov edx, [ecx]        ; copy one more.
;   mov [esp], edx
; 
;   jmp eax

[EXTERN executeRpcRequests]
[GLOBAL executeRpcRequestsWrapper]
executeRpcRequestsWrapper:
  push edi ; Push process
  push esi ; Push call
  call executeRpcRequests
  int 0x3  ; Should never get here.

[EXTERN resolveSymbol]
[GLOBAL resolveSymbol_asm]
resolveSymbol_asm:
  call resolveSymbol
  pop ecx               ; Remove library ID parameter
  pop ecx               ; Remove symbol offset parameter
  jmp eax

#endif // LANG_X86
